#ifndef NETADDRESS_H
#define NETADDRESS_H

#include <cstdint>
#include <string>
#include "Utils.h"

struct sockaddr;
struct sockaddr_in;
namespace tool{ namespace net{

//host order
uint32_t TransAddr(const char* addr);
std::string TransAddr(uint32_t addr);

using AddrID = uint64_t;

namespace detail{
union UTranslator{
    AddrID key;
    struct{
        uint32_t ip;
        uint16_t port;
        uint16_t reserved;
    }addr;

    UTranslator(AddrID id)
        :key(id) {}
    UTranslator(uint32_t ip,uint16_t port)
        :addr({ip,port,0}) {}
};
}

//host order ip and port
class NetAddress{
public:
    constexpr NetAddress()
        :m_ip(0),m_port(0)
    {}

    constexpr NetAddress(uint32_t hIp,uint16_t uiPort)
        :m_ip(hIp),m_port(uiPort)
    {}

    NetAddress(const char* strIp,uint16_t iPort)
        :m_ip(TransAddr(strIp)),m_port(iPort)
    {}

    //str format "ip:port"
    NetAddress(const std::string& str);

    explicit NetAddress(const sockaddr *sock);
    explicit NetAddress(const sockaddr_in *sock);

    explicit NetAddress(AddrID key)
    {
        detail::UTranslator u(key);
        m_ip = u.addr.ip;
        m_port = u.addr.port;
    }

    AddrID toKey() const
    {
        detail::UTranslator u(m_ip,m_port);
        return u.key;
    }

    std::string toString() const;

    uint16_t port() const
    { return m_port; }

    std::string ipString() const
    { return TransAddr(m_ip); }

    uint32_t ipValue() const
    { return m_ip; }

    bool operator==(const NetAddress& rhs) const{
        return (m_port == rhs.m_port) && (m_ip == rhs.m_ip);
    }
private:
    uint32_t m_ip;
    uint16_t m_port;
};

}}//namespcae net::tool


#endif // NETADDRESS_H
